# -*- shell-script -*-

# 30device-tree - Hardware database scanning routines and variables for
#                 systems with device-tree, with or without ibm,vpd properties.

# This file is part of the Linux lsvpd package.

# (C) Copyright IBM Corp. 2002, 2003, 2004, 2005

# Maintained by Martin Schwenke <martins@au.ibm.com>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    
# $Id: 30device-tree,v 1.1 2006/04/11 18:38:28 emunson Exp $

source_device_tree="/proc/device-tree"
[ -f "${source_device_tree}/system-id" ] || source_device_tree=""

[ -n "$source_device_tree" ] || return 0

######################################################################

source_root="$source_device_tree"

if [ -f "${source_device_tree}/device_type" ] ; then
    read device_tree_device_type <"${source_device_tree}/device_type"
fi

db_subdir_vars_hooks="${db_subdir_vars_hooks} db_set_subdir_vars_dt"
db_set_subdir_vars_dt

db_initialise_bus ()
{
    # FIXME: Try testing with this disabled to test "hotplug" code.
    ensure_directory "$db_bus_dir"
    debug_cmd cp -a "$source_device_tree" "$db_bus_dt_dir"
}

######################################################################

adapter_set_ds ()
{
    # Sets: ds

    local bus_type="$1"
    local bus_addr="$2"
    local subtype="$3"

    adapter_set_ds_basic "$subtype"

    local source_node=""
    adapter_get_source_node "$bus_type" "$bus_addr" "$subtype"

    local f="${source_node}/ibm,fw-adapter-name"
    local ibm_name
    [ -r "$f" ] && read ibm_name <"$f"

    case "$subtype" in
	scsi|ibmvscsi)
	    # FIXME: lost $ibm_name for channel?
	    [ -n "$ibm_name" ] && ds="${ibm_name} ${ds}"
	    [ -e "${source_node}/wide" ] && ds="Wide/${ds}"
	    ;;
	ethernet|ibmveth)
	    [ -n "$ibm_name" ] && ds="$ibm_name"
	    ;;
    esac
}

######################################################################

adapter_retrieve_logicals_vpd ()
{
    local bus_type="$1"
    local bus_addr="$2"
    local node="$3"

    local subtype
    retrieve_subtype_basic "$node"
    [ -n "$subtype" ] || return 1  ### !!!
    
    local source_node
    adapter_get_source_node "$bus_type" "$bus_addr" "$subtype"
    [ -n "$source_node" ] ||  return 1 ### !!!

    local dt_adapter_subdirs
    get_dt_adapter_subdirs

    # FIXME: This is prematurely optimised to stop after finding a
    # candidate subdir@0 and just checking that.  If an adapter
    # (iSCSI?) can have multiple channels types then things get
    # interesting...
    local subdirs=""
    cd "$source_node"
    local i
    for i in $dt_adapter_subdirs ; do
	if [ -d "${i}@0" ] ; then
	    # FIXME: limit of 100000 adapters!  :-)
	    local j
	    for j in "${i}@"? "${i}@"?? "${i}@"??? "${i}@"???? "${i}@"????? ; do
		[ -d "$j" ] && \
		    subdirs="${subdirs} ${j}"
	    done
	    break
	fi
    done
    subdirs="${subdirs# }" # Remove "accidently" added leading space.
    cd "$OLDPWD"

    # If there's more than one subdirectory, remember the details of
    # channels and subdirectories in lsvpd,logicals.
    if [ "$subdirs" != "${subdirs#* }" ] ; then
	local f="${node}/lsvpd,logicals"
	>"$f"
	local i
	for i in $subdirs ; do
	    local hex="${i##*@}"
	    local num=$(hex2dec "$hex")
	    echo "${num} ${i}" >>"$f"
	done
    fi

    adapter_retrieve_logicals_common \
	"$bus_type" "$bus_addr" "$subtype" "$node" "$subdirs"
}

######################################################################

adapter_extra_vpd_hooks="${adapter_extra_vpd_hooks} dt_mac_address_vpd_hook"

dt_mac_address_vpd_hook ()
{
    # Sets: key val
    key="" ; val=""

    local bus_type="$1"
    local bus_addr="$2"
    local subtype="$3"

    case "$subtype" in
	(ethernet|ibmveth) : ;;
	(*) return 0 ;;
    esac

    local source_node 
    adapter_get_source_node "$bus_type" "$bus_addr" "$subtype"

    local props="mac-address local-mac-address"
    local p
    for p in $props ; do
	local f="${source_node}/${p}"
	if [ -f "$f" ] ; then
	    local mac_address=$(tdump -c "$f")
	    if [ -n "$mac_address" ] ; then
			key="NA"
			val="$mac_address"
			vpd_function="vpd_field_ensure"
			break
	    fi
	fi
	
    done
}

######################################################################

get_dt_adapter_subdirs ()
{
    # Sets: dt_adapter_subdirs
    dt_adapter_subdirs=""
    dt_adapter_subdirs="${dt_adapter_subdirs} scsi fibre-channel v-scsi k2-sata"
    dt_adapter_subdirs="${dt_adapter_subdirs} ethernet l-lan"
    dt_adapter_subdirs="${dt_adapter_subdirs} ide ata-6"
    dt_adapter_subdirs="${dt_adapter_subdirs} usb"
    dt_adapter_subdirs="${dt_adapter_subdirs} display"
    dt_adapter_subdirs="${dt_adapter_subdirs} serial"
}
